﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FALibrary.Sequence
{
    public enum SequenceState
    {
        Available, Running, Idle, Starting, Terminated, Suspeded, Suspending, Alarm
    }

    public class StepInfo
    {
        public int StepIndex { get; set; }
    }

    public class FASequence : FAObject
    {
        private SequenceState _state = SequenceState.Available;
        private FASequenceItem _currentItem = null;
        private Dictionary<string, StepInfo> _steps = new Dictionary<string, StepInfo>();
        private List<Action<FASequence, long>> _sequenceWatcherList = new List<Action<FASequence, long>>();
        private List<FASequenceItem> _sequenceList = new List<FASequenceItem>();

        public FASequence()
        {
            FAAutoNextSequenceItem startItem = new FAAutoNextSequenceItem(StartSequence);
            FAAutoNextSequenceItem terminateItem = new FAAutoNextSequenceItem(TerminateSequence);
            _sequenceList.Add(startItem);
            _sequenceList.Add(terminateItem);
        }

        public SequenceState State
        {
            get
            {
                return _state;
            }

            private set
            {
                _state = value;
            }
        }

        public int CurrentItemIndex
        {
            get
            {
                return _sequenceList.IndexOf(_currentItem);
            }
        }

        public Dictionary<string, StepInfo> Steps
        {
            get
            {
                return _steps;
            }
        }

        public void AddWatcher(Action<FASequence, long> method)
        {
            _sequenceWatcherList.Add(method);
        }

        public int AddItem(Action<FASequence, long> actor)
        {
            FAConditionalSequenceItem item = new FAConditionalSequenceItem(actor);
            _sequenceList.Insert(_sequenceList.Count - 1, item);
            return _sequenceList.Count - 2;
        }

        public int AddItem(Action<object> actor)
        {
            FAAutoNextSequenceItem item = new FAAutoNextSequenceItem(actor);
            _sequenceList.Insert(_sequenceList.Count - 1, item);            
            return _sequenceList.Count - 2;
        }

        public int AddItem(params FASequence[] sequences)
        {
            FASequenceCombinationSequenceItem item = new FASequenceCombinationSequenceItem(sequences);
            _sequenceList.Insert(_sequenceList.Count - 1, item);
            return _sequenceList.Count - 2;
        }

        public bool Start(object sender)
        {
            if (State == SequenceState.Terminated)
                _state = SequenceState.Available;

            if (State == SequenceState.Available)
            {
                _state = SequenceState.Running;
                _currentItem = _sequenceList[0];
                return true;
            }

            return false;
        }

        public void Stop()
        {
        }

        public void SetAlarm()
        {
        }

        public void Suspend()
        {
        }

        public void Resume()
        {
        }

        public void Abort()
        {
        }

        public void Retry()
        {
            _currentItem = _sequenceList[0];
        }

        public void NextStep()
        {
            _currentItem = _sequenceList[CurrentItemIndex + 1];
            _currentItem.ClearState();
        }

        public void NextStep(string stepName)
        {
            if (Steps.ContainsKey(stepName))
            {
            }
            else
            {
                _currentItem = _sequenceList[ Steps[stepName].StepIndex ];
                _currentItem.ClearState();
            }
        }

        public void NextTerminate()
        {
            _currentItem = _sequenceList[_sequenceList.Count - 1];
            _currentItem.ClearState();
        }

        private void StartSequence(object actor)
        {            
        }

        private void TerminateSequence(object actor)
        {
        }
    }
}
